#include "OldProfiler.h"
#include "Log.h"
#include "..\renderer\DebugRenderer.h"

//Profiler* gProfiler;

Profiler::Profiler(void) {
	QueryPerformanceFrequency(&frequency);

	m_Root = new ProfileNode();
    m_Root->parent = 0;
    m_Root->duration = 0.0;
    m_Root->accu = 0.0;
    m_Root->name = "ROOT";
	QueryPerformanceCounter(&m_Root->started);
    m_Current = m_Root;
}


Profiler::~Profiler(void) {
}

double Profiler::LIToSecs( LARGE_INTEGER & L) {
     return ((double)L.QuadPart * 1000.0 /(double)frequency.QuadPart) ;
 }
 
 void Profiler::start(const std::string& name) {
	 //Profile* p = getProfile(name);
	 //++p->calls;	 	 
     //QueryPerformanceCounter(&p->timer.start) ;

	 // check if we have the profile and then increase the number
    // of total calls
    Frames::iterator iter;
    for ( iter = m_Frames.begin(); iter != m_Frames.end(); ++iter) {
        if ( (*iter).name == name ) {
            ++(*iter).calls;
            break;
        }
    }
    if ( iter == m_Frames.end() ) {
        ProfileFrame pf;
        pf.calls = 1;
        pf.duration = 0.0;
        pf.name = name;
        m_Frames.push_back(pf);
    }        
    
    // create a new node and add it to the current
    // profile node as child
    ProfileNode* node = new ProfileNode();
    node->parent = m_Current;
    node->name = name;
    node->duration = 0.0;
    node->accu = 0.0;
    QueryPerformanceCounter(&node->started);
    m_Current->children.push_back(node);
    m_Current = node;
 }
 
 void Profiler::end(const std::string& name) {
	LARGE_INTEGER stop;
	QueryPerformanceCounter(&stop);
	LARGE_INTEGER time;
	time.QuadPart = stop.QuadPart - m_Current->started.QuadPart;

	m_Current->duration = LIToSecs(time);    
	Frames::iterator iter;
    for ( iter = m_Frames.begin(); iter != m_Frames.end(); ++iter) {
        if ( (*iter).name == name ) {
            (*iter).duration += m_Current->duration;
        }
    }
    
    ProfileNode* parent = m_Current->parent;    
    while ( parent != 0 ) {
        parent->accu += m_Current->duration;
        parent = parent->parent;
    }
    m_Current = m_Current->parent;       
 }
 
 void Profiler::reset() {
	 // create history
	 for (size_t i = 0; i < m_Frames.size(); ++i) {
        ProfileFrame* pf = &m_Frames[i];  
		pf->calls = 0;
		pf->duration = 0.0;
	 }
	 resetNodes(m_Root->children);
	 m_Root->duration = 0.0;
	 m_Root->accu = 0.0;
	 m_Root->children.clear();

 }

 void Profiler::resetNodes(const std::vector<ProfileNode*>& nodes) {
	 for ( size_t i = 0; i < nodes.size(); ++i ) {
        ProfileNode* pn = nodes[i];		
        if ( pn->children.size() > 0 ) {
            resetNodes(pn->children);
        }
		pn->children.clear();
		delete pn;
    }
 }

 std::string Profiler::fillString(const std::string& txt,int length) {
	 std::string ret = txt;
	 int len = length - ret.length();
	 if ( len > 0 ) {
		 for ( int i = 0; i < len; ++i ) {
			 ret.append(" ");
		 }
	}
	return ret;	
 }

 void Profiler::print() {
	 //std::sort(m_Frames,sortFrames);	 
	LOGC(logINFO,"Profiler") << "Overview: ";
	int max = 0;
	for (size_t i = 0; i < m_Frames.size(); ++i) {
		ProfileFrame* pf = &m_Frames[i];
		if ( pf->name.length() > max ) {
			max = pf->name.length();
		}
	}
	for (size_t i = 0; i < m_Frames.size(); ++i) {
		ProfileFrame* pf = &m_Frames[i];       
		LOG(logINFO) << fillString(pf->name,max+2) << " : " << pf->calls << " : " << pf->duration;
	}    
	double total = m_Root->children[0]->accu;
	LOGC(logINFO,"Profiler") << "Tree: ";
    printNodes(m_Root->children,0,total);
}

float Profiler::calculatePercentage(double current,double total) {
	return current / total * 100.0;
}

void Profiler::printNodes(const std::vector<ProfileNode*>& nodes, int lvl,double total) {
    for ( size_t i = 0; i < nodes.size(); ++i ) {
        ProfileNode* pn = nodes[i];
		std::string str = "";
        for (int j = 0; j < lvl * 2; ++j) {
                str += " ";
        }         
        if ( pn->children.size() > 0 ) {
			LOG(logINFO) << str << pn->name << " : " << pn->accu << " : " << calculatePercentage(pn->accu,total) << "%";
            printNodes(pn->children,lvl+1,total);
        }
		else {
			LOG(logINFO) << str << pn->name << " : " << pn->duration << " : " << calculatePercentage(pn->duration,total) << "%";
		}
    }
}

void Profiler::debug() {	
	double total = m_Root->children[0]->accu;
	debugNodes(m_Root->children,0,total,50);
}

void Profiler::debugNodes(const std::vector<ProfileNode*>& nodes, int lvl,double total,int y) {
	for ( size_t i = 0; i < nodes.size(); ++i ) {
		ProfileNode* pn = nodes[i];
		int x = lvl * 20;				
		gEngine->getDebugRenderer()->addText(ds::Vec2(x,y),ds::Color(1.0f,1.0f,1.0f,1.0f),"%s : %2.5f  / %2.5f / %3.2f",pn->name.c_str(),pn->duration,pn->accu,calculatePercentage(pn->duration,total));
		y += 12;
		if ( pn->children.size() > 0 ) {
			debugNodes(pn->children,lvl+1,total,y);
		}
	}
}
